

var defaultValue = Cesium.defaultValue;
var SceneMode = Cesium.SceneMode;

import gsap from "gsap";


function HighPowerPrimitive(options) {
    options = defaultValue(options, defaultValue.EMPTY_OBJECT);
    this.show = defaultValue(options.show, true);

    this.modelMatrix = Cesium.Matrix4.clone(options.modelMatrix, new Cesium.Matrix4());
    this._modelMatrix = new Cesium.Matrix4();

    this.color = defaultValue(options.color, Cesium.Color.WHITE);
    this._color = Cesium.Color.WHITE;

    this.lineColor = defaultValue(options.color, Cesium.Color.WHITE);
    this._lineColor = Cesium.Color.WHITE;

    this.height = defaultValue(options.color, 0);
    this._height = 0;

    this.radius = defaultValue(options.radius, 0);
    this._radius = 0;


    this.heightInterval = defaultValue(options.heightInterval, 0);
    this._heightInterval = 0;

    this.radiusInterval = defaultValue(options.radiusInterval, 0);
    this._radiusInterval = 0;

    this.showLine = defaultValue(options.color, true);
    // this._showLine = false;

    this.showScanPlane = defaultValue(options.color, false);
    // this._showScanPlane = false;

    this.ScanPlaneColor = defaultValue(options.color, Cesium.Color.WHITE);
    this._ScanPlaneColor = Cesium.Color.WHITE;

    this.ScanPlaneSwitch = defaultValue(options.color, false);
    this._ScanPlaneSwitch = false;

    this.ScanPlaneSpeed = defaultValue(options.color, 10);
    this._ScanPlaneSpeed = 10


    this.vs = `
    attribute vec4 position;
    attribute vec3 normal;
    
    varying vec3 v_position;
    varying vec3 v_positionWC;
    varying vec3 v_positionEC;
    varying vec3 v_normalEC;
    
    void main()
    {
        gl_Position = czm_modelViewProjection * position;
        v_position = vec3(position);
        v_positionWC = (czm_model * position).xyz;
        v_positionEC = (czm_modelView * position).xyz;
        v_normalEC = czm_normal * normal;
    }`;
    this.fs = this.renderFS(this._color);
    this.fs_line = this.renderFS(this._lineColor);
    this.fs_ScanPlane = this.renderFS(this._ScanPlaneColor);
    this.percentage = 0;
    this._gsap = null;

}
HighPowerPrimitive.prototype.renderFS = function (color) {
    return `void main(){gl_FragColor=vec4(${color.red},${color.green},${color.blue},${color.alpha});}`;
}
HighPowerPrimitive.prototype.runScanPlane = function () {
    if (this._ScanPlaneSwitch != this.ScanPlaneSwitch) {
        this._ScanPlaneSwitch = this.ScanPlaneSwitch;
        if (this.ScanPlaneSwitch) {
            this.percentage = 0;
            this._gsap = gsap.to(this, {
                percentage: 1, duration: this._ScanPlaneSpeed, repeat: -1,
                ease: "none"
            });
        } else {
            this._gsap.pause();
            this._gsap.kill();
        };
    }

    if (this.ScanPlaneSpeed != this._ScanPlaneSpeed) {
        this._ScanPlaneSpeed = this.ScanPlaneSpeed;
        this._gsap.kill();
        this.percentage = 0;
        this._gsap = gsap.to(this, {
            percentage: 1, duration: this._ScanPlaneSpeed, repeat: -1,
            ease: "none"
        });
    }
}
HighPowerPrimitive.prototype.isDestroyed = function () {
    return false
}
HighPowerPrimitive.prototype.destroy = function () {

}
HighPowerPrimitive.prototype.update = function (frameState) {
    var mode = frameState.mode;
    if (!this.show || mode !== SceneMode.SCENE3D) {
        return;
    }
    var isRender = false;
    if (this.color) {
        if (!this.color.equals(this._color)) {
            isRender = true;
            this._color = this.color;
            this.fs = this.renderFS(this._color);
        };
    }
    if (this.lineColor) {
        if (!this.lineColor.equals(this._lineColor)) {
            isRender = true;
            this._lineColor = this.lineColor;
            this.fs_line = this.renderFS(this._lineColor);
        };
    }
    if (this.ScanPlaneColor) {
        if (!this.ScanPlaneColor.equals(this._ScanPlaneColor)) {
            isRender = true;
            this._ScanPlaneColor = this.ScanPlaneColor;
            this.fs_ScanPlane = this.renderFS(this._ScanPlaneColor);
        };
    }
    if (this.modelMatrix != this._modelMatrix) {
        isRender = true;
        this._modelMatrix = this.modelMatrix;
    };

    if (this.height != this._height) {
        this._height = this.height;
    }
    if (this.lineColor != this._lineColor) {
        this._lineColor = this.lineColor;
    }
    if (this.radius != this._radius) {
        this._radius = this.radius;
    }
    if (this.heightInterval != this._heightInterval) {
        this._heightInterval = this.heightInterval;
    }
    if (this.radiusInterval != this._radiusInterval) {
        this._radiusInterval = this.radiusInterval;
    }

    var commandList = frameState.commandList

    var _point = CreateBarrelVertexArray(this._height, this._radius, this._radiusInterval);
    var pointCommand = getCommand(this.vs, this.fs, frameState, _point, this._modelMatrix, false);
    commandList.push(pointCommand);

    if (this.showLine) {
        var _line = CreateLineVertexArray(this._height, this._radius, this._heightInterval, this._radiusInterval);
        var lineCommand = getCommand(this.vs, this.fs_line, frameState, _line, this._modelMatrix, true);
        commandList.push(lineCommand);
    }

    if (this.showScanPlane) {
        var _ScanPlane = CreateScanPlaneVertexArray(this._height * this.percentage, this._radius, this._radiusInterval);
        var ScanPlaneCommand = getCommand(this.vs, this.fs_ScanPlane, frameState, _ScanPlane, this._modelMatrix, false);
        commandList.push(ScanPlaneCommand);
    }

    if (this._ScanPlaneSwitch != this.ScanPlaneSwitch || this.ScanPlaneSpeed != this._ScanPlaneSpeed) {
        this.runScanPlane();
    }
}

var CX = function (radius, angle) {
    return radius * Math.cos(angle);
}
var CY = function (radius, angle) {
    return radius * Math.sin(angle);
}

var radian2angle = function (angle) {
    return angle * Math.PI / 180;
}

var computeRadius = function (height, radius, radiusInterval) {
    var point = [];
    for (let i = 0; i < 360; i += radiusInterval) {
        var a = 0;
        if (i > 360) {
            a = 360
        } else {
            a = i
        };
        var radian = radian2angle(a);
        point.push([CX(radius, radian), CY(radius, radian), height]);
    };
    return point;
}

var CreateBarrelVertexArray = function (height, radius, radiusInterval) {
    var topPoints = computeRadius(height, radius, radiusInterval);
    var bottomPoints = computeRadius(0, radius, radiusInterval);
    var arr = [];
    for (let i = 0; i < topPoints.length; i++) {
        let nextLength = i + 1 == topPoints.length ? 0 : i + 1;
        const top = topPoints[i];
        const topNext = topPoints[nextLength];
        const bottom = bottomPoints[i];
        const bottomNext = bottomPoints[nextLength];
        arr.push(top[0], top[1], top[2]);
        arr.push(topNext[0], topNext[1], topNext[2]);
        arr.push(bottom[0], bottom[1], bottom[2]);
        arr.push(bottom[0], bottom[1], bottom[2]);
        arr.push(bottomNext[0], bottomNext[1], bottomNext[2]);
        arr.push(topNext[0], topNext[1], topNext[2]);
    }
    return arr;
}


var CreateLineVertexArray = function (height, radius, heightInterval, radiusInterval) {
    var lineArray = [];
    var arr = [];
    var count = parseInt(height / heightInterval);
    for (let i = 0; i < count + 1; i++) {
        lineArray.push(i * heightInterval);
    }
    if (lineArray[lineArray.length - 1] != height) {
        lineArray.push(height);
    }

    for (let i = 0; i < lineArray.length; i++) {
        const _height = lineArray[i];
        let topPoints = computeRadius(_height, radius, radiusInterval);
        for (let i = 0; i < topPoints.length; i++) {
            let nextLength = i + 1 == topPoints.length ? 0 : i + 1;
            const element = topPoints[i];
            const elementNext = topPoints[nextLength];
            arr.push(element[0], element[1], element[2]);
            arr.push(elementNext[0], elementNext[1], elementNext[2]);
        }
    }


    var angleArray = [];
    var angleCount = parseInt(360 / radiusInterval);
    for (let i = 0; i < angleCount + 1; i++) {
        angleArray.push(i * radiusInterval);
    }
    if (angleArray[angleArray.length - 1] != 360) {
        angleArray.push(360);
    }
    if (angleArray.length > 3) {
        for (let i = 0; i < angleArray.length; i++) {
            const element = angleArray[i];
            var radian = radian2angle(element);
            arr.push(CX(radius, radian), CY(radius, radian), 0);
            arr.push(CX(radius, radian), CY(radius, radian), height);
        };
    };

    return arr;
}

var CreateScanPlaneVertexArray = function (height, radius, radiusInterval) {
    var arr = [];
    for (let i = 0; i < 360; i += radiusInterval) {
        var a = i > 360 ? 360 : i;
        var radian = radian2angle(a)
        var nexta = a + radiusInterval > 360 ? 360 : a + radiusInterval;
        var next_radian = radian2angle(nexta);
        arr.push(0, 0, height);
        arr.push(CX(radius, radian), CY(radius, radian), height);
        arr.push(CX(radius, next_radian), CY(radius, next_radian), height);
    }
    return arr;
}


//用prototype给定方法和属性
var getCommand = function (v, f, frameState, arr, modelMatrix, isLine) {
    var context = frameState.context;
    //shaderProgram将两个着色器合并
    var shaderProgram = Cesium.ShaderProgram.fromCache({
        context: context,
        vertexShaderSource: v,
        fragmentShaderSource: f
    })
    //渲染状态
    var renderState = Cesium.RenderState.fromCache({
        depthTest: {
            enabled: true
        },
        depthMask: false,
        blending: Cesium.BlendingState.ALPHA_BLEND
    })
    //顶点数组Buffer
    var vertexBuffer = Cesium.Buffer.createVertexBuffer({
        context: context,
        typedArray: Cesium.ComponentDatatype.createTypedArray(
            Cesium.ComponentDatatype.FLOAT,
            arr,
        ),
        usage: Cesium.BufferUsage.STATIC_DRAW
    })
    //用来表示逐个顶点的信息
    var attributes = []
    attributes.push({
        index: 0,
        vertexBuffer: vertexBuffer,
        componentDatatype: Cesium.ComponentDatatype.FLOAT,
        componentsPerAttribute: 3,
        normalize: false
    })
    //顶点数组（设置顶点属性和索引Buffer）
    var vertexArray = new Cesium.VertexArray({
        context: context,
        attributes: attributes,
    })

    //新建一个DrawCommand
    return new Cesium.DrawCommand({
        // 渲染线类型
        // primitiveType: Cesium.PrimitiveType.LINES,
        // 渲染面类型
        primitiveType: isLine ? Cesium.PrimitiveType.LINES : Cesium.PrimitiveType.TRIANGLES,
        shaderProgram: shaderProgram,
        renderState: renderState,
        vertexArray: vertexArray,
        pass: Cesium.Pass.OPAQUE,
        modelMatrix: modelMatrix,
    })
}


export { HighPowerPrimitive }